<?php

// Namespace

namespace Loop;


// Dependencies

require_once(PATH_LOOP . 'Model/CProfilingEvent.php');


/**
 * @package		Loop
 * @category	Model
 */

class CProfilingThread extends \Loop\CObject
{
	// Properties

	public $profilingEvents = null;
	public $profilingStep = null;


	/**
	 *
	 */
	
	protected function createProperties()
	{
		$this->createProperty
		(
			'cookieVariables',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'getVariables',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'httpRequestVariables',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'httpResponseVariables',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'maxMemory',
			array
			(
				'type' => TYPE_INTEGER_UNSIGNED
			)
		);

		$this->createProperty
		(
			'nbQueries',
			array
			(
				'type' => TYPE_INTEGER_UNSIGNED
			)
		);

		$this->createProperty
		(
			'pathToView',
			array
			(
				'type' => TYPE_STRING_LONG
			)
		);

		$this->createProperty
		(
			'postVariables',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'preferences',
			array
			(
				'type' => TYPE_TEXT_LONG
			)
		);

		$this->createProperty
		(
			'profilingEvents',
			array
			(
				'className' => 'CProfilingEvent',
				'extensionId' => EXTENSION_LOOP,
				'isComposition' => true,
				'isDirect' => true
			)
		);

		$this->createProperty
		(
			'profilingProcessKey',
			array
			(
				'type' => TYPE_STRING_LONG
			)
		);

		$this->createProperty
		(
			'sessionVariables',
			array
			(
				'type' => TYPE_TEXT
			)
		);

		$this->createProperty
		(
			'timeOfClosure',
			array
			(
				'type' => TYPE_REAL_UNSIGNED
			)
		);

		$this->createProperty
		(
			'timeOfStart',
			array
			(
				'type' => TYPE_REAL_UNSIGNED
			)
		);
	}


	/**
	 *
	 */

	public function getDuration()
	{
		return $this->getTimeOfClosure() - $this->getTimeOfStart();
	}


	/**
	 *
	 */

	public function getRawProfilingEvents()
	{
		//

		$profilingEvent = new \Loop\CProfilingEvent();

		$rawProfilingEvents = $profilingEvent->find
		(
			array
			(
				'conditions' => array
				(
					'profilingThreadId' => array(EQUAL, $this->getId())
				),
				'orderBy' => array('timeOfStart'),
				'orderDirection' => 'ascendent'
			)
		);


		return $rawProfilingEvents;
	}


	/**
	 *
	 */

	public function isStarted()
	{
	}


	/**
	 *
	 */

	public function reset()
	{
		//

		parent::reset();


		//

		$this->profilingEvents = array();
		$this->profilingStep = PROFILING_STEP_INIT;
	}


	/**
	 *
	 */

	public function save($objectProperties = null, $languageIsoCode = null)
	{
		//

		parent::save($objectProperties, $languageIsoCode);


		//

		foreach ($this->profilingEvents as $profilingEventUuid => &$profilingEvent)
		{
			$profilingEvent->setProfilingThreadId($this->getId());
			$profilingEvent->save();
		}
	}


	/**
	 *
	 */

	public function stop()
	{
		//

		$this->setMaxMemory(memory_get_peak_usage());
		$this->setTimeOfClosure(microtime(true));
	}


	/**
	 *
	 */

	public function setStep($step)
	{
		$this->profilingStep = $step;
	}


	/**
	 *
	 */

	public function startEvent($eventType = null, $eventMessage = null, $eventInput = null)
	{
		// Is profiling allowed?

		if (app()->getProfilingManager()->isProfilingAllowed() === false)
		{
			return;
		}


		// Find the relevant trace

		$functions = array('plog', 'pstart', 'pstop');
		$traces = debug_backtrace();
		$finalTrace = array
		(
			'file' => null,
			'line' => null
		);

		foreach ($traces as $trace)
		{
			if (in_array($trace['function'], $functions) === true)
			{
				$finalTrace = $trace;
				break;
			}
		}


		// Compute a UUID for this event

		$profilingEventUuid = app()->getStringHelper()->generateUuid();


		// Event does not exist yet

		$profilingEvent = new \Loop\CProfilingEvent();

		if (empty($eventInput) === false)
		{
			$profilingEvent->setInput(json_encode($eventInput));
		}

		$profilingEvent->setLineOfStart($finalTrace['line']);
		//$profilingEvent->setMaxMemory(memory_get_peak_usage());
		$profilingEvent->setPathToFileOfStart($finalTrace['file']);
		$profilingEvent->setTimeOfStart(microtime(true));
		$profilingEvent->setType($eventType);


		//

		if ($eventType === PROFILING_TYPE_QUERY)
		{
			$this->setNbQueries($this->getNbQueries() + 1);
		}


		// Store the event

		$this->profilingEvents[$profilingEventUuid] = $profilingEvent;


		return $profilingEventUuid;
	}


	/**
	 *
	 */

	public function stopEvent($eventUuid, $eventOutput)
	{
		// Does the event exist?

		if (isset($this->profilingEvents[$eventUuid]) === false)
		{
			e
			(
				EXCEPTION_PROFILING_EVENT_NOT_FOUND,
				array
				(
					'eveentUuid' => $eventUuid
				)
			);
		}


		// Find the relevant trace

		$functions = array('plog', 'pstart', 'pstop');
		$traces = debug_backtrace();
		$finalTrace = array
		(
			'file' => null,
			'line' => null
		);

		foreach ($traces as $trace)
		{
			if (in_array($trace['function'], $functions) === true)
			{
				$finalTrace = $trace;
				break;
			}
		}


		// Get the event and stop it

		$profilingEvent = $this->profilingEvents[$eventUuid];

		if (empty($eventOutput) === false)
		{
			$profilingEvent->setOutput(json_encode($eventOutput));
		}

		$profilingEvent->setLineOfClosure($finalTrace['line']);
		$profilingEvent->setMaxMemory(memory_get_peak_usage());
		$profilingEvent->setStep($this->profilingStep);
		$profilingEvent->setPathToFileOfClosure($finalTrace['file']);
		$profilingEvent->setTimeOfClosure(microtime(true));
	}
}

?>
